<?php
/**
 * 
 */

/**
 * 
 */

/**
 * Handle the session data for users
 *
 * @author anthony
 */
class UserSession {
    protected $session_id = false;
    protected $userid = false;
    protected $start_time = false;
    protected $end_time = false;
    protected $ip = false;
    
    protected $db_hit = false;
    protected $verified = false;
    
    protected $max_session_length = 3600; // In seconds
    protected $cookie_name = "sessx";
    
    public function __construct() {}
    public function __destruct() {}
    
    public static function countActiveSessions() {
        global $sql_conx;
        
        $active_session_expire = time() + 3600 - 300;
        $query = $sql_conx->query("SELECT COUNT(`userid`) FROM `srv_session` WHERE `end_time` > '{$active_session_expire}';");
        if($query !== false && $query->num_rows > 0) {
            $row = $query->fetch_row();
            return $row[0];
        } else {
            return -1;
        }
    }
    
    /**
     * Create a session for the given username
     * WARNING: Do not pass unpacified $userids, $sql_conx->real_escape_string($userid) FIRST.
     * @global type $sql_conx
     * @global type $_SERVER
     * @param type $userid 
     */
    public function createNewSession($userid) {
	global $sql_conx, $_SERVER;
	
	// Trigger a collection on all expired session data.
	$this->garbageCollection();
	$i = 0;
	
	// Make 3 attempts to create a session - it can fail if there is a md5 clash
	// Multiple failures would denote a problem
	while($i < 3) {
	    $md5_key = md5((time() + microtime()));
	    $md5_key_safe = $sql_conx->real_escape_string($md5_key);
	    $start_time = time();
	    $end_time = time()+3600;
	    $ip = $sql_conx->real_escape_string($_SERVER['REMOTE_ADDR']);
	    
	    $this->triggerGarbageCollectionByUserID($userid); // Delete this users session data if it exists
	    $query = $sql_conx->query("INSERT INTO `srv_session` ( `sessionid` , `userid` , `start_time` , `end_time` , `IP` ) VALUES ( '{$md5_key_safe}',  '{$userid}',  '{$start_time}',  '{$end_time}',  '{$ip}' )");
	    if($sql_conx->affected_rows > 0) {
		$this->session_id = $md5_key;
		$this->userid = $userid;
		$this->start_time = $start_time;
		$this->end_time = $end_time;
		$this->ip = $_SERVER['REMOTE_ADDR'];
		$this->db_hit = true;
		$this->verified = true;
		$this->updateCookie();
		$i = 4;
	    }
	    $i++;
	}
    }
    
    public function destroySession() {
	$this->triggerGarbageCollectionBySessionID($this->session_id);
	$this->updateCookie(true);
    }
    
    /**
     * Verify the session id - this adds as a "session is live" indicator when a page is loaded, we extend expiry time.
     * WARNING: Do not pass unpacified $userids, $sql_conx->real_escape_string($userid) FIRST.
     * @param type $session_id
     * @return boolean 
     */
    public function verifySession($session_id) {
	global $sql_conx;
	
	if($this->db_hit === false) {
	    $query = $sql_conx->query("SELECT `userid`, `end_time`, `IP` FROM `srv_session` WHERE `sessionid`='{$session_id}'");
	    if($query !== false && $query->num_rows > 0) {
		global $_SERVER;
		$now = time();
		$ip = $_SERVER['REMOTE_ADDR'];
		$row = $query->fetch_assoc();
		//die($row['end_time'].':'.$now.' || '.$ip.':'.$row['IP']);
		if($row['end_time'] > $now && $ip == $row['IP']) {
		    $new_end_time = $sql_conx->real_escape_string(time()+$this->max_session_length);
		    $query = $sql_conx->query("UPDATE `srv_session` SET `end_time`='{$new_end_time}' WHERE `sessionid`='{$session_id}' LIMIT 1;");
		    $query = $sql_conx->query("SELECT `userid` , `start_time` , `end_time` , `IP` FROM `srv_session` WHERE `sessionid`='{$session_id}';");
		    if($query !== false && $query->num_rows > 0) {
			$row = $query->fetch_assoc();
			$this->session_id = $session_id;
			$this->userid = $row['userid'];
			$this->start_time = $row['start_time'];
			$this->end_time = $row['end_time'];
			$this->ip = $row['IP'];
			$this->db_hit = true;
			$this->verified = true;
			$this->updateCookie();
			$i = 4;
		    }
		    $this->verified = true;
		} else {
		    // Session Verification Failed - Delete the session, Delete their cookie
		    $this->triggerGarbageCollectionByUserID($row['userid']);
		    $this->updateCookie(true);
		}
	    }
	    $this->db_hit = true;
	}
	return $this->verified;
    }
    
    /**
     * Updates the cookie for the current user 
     */
    final protected function updateCookie($destroy = false) {
	if($destroy === true) {
	    setcookie($this->cookie_name, $this->session_id, 1, '/');
	} else {
	    setcookie($this->cookie_name, $this->session_id, (time()+$this->max_session_length), '/');
	}
    }
    
    /**
     * If a users session is needing to be deleted, delete it.
     * @global type $sql_conx
     * @param type $userid 
     */
    final protected function triggerGarbageCollectionByUserID($userid) {
	global $sql_conx;
	/*$userid = $sql_conx->real_escape_string($userid);*/
	$query = $sql_conx->query("DELETE FROM `srv_session` WHERE `userid`='{$userid}';");
    }
    
    final protected function triggerGarbageCollectionBySessionID($sessionID) {
	global $sql_conx;
	/*$userid = $sql_conx->real_escape_string($userid);*/
	$query = $sql_conx->query("DELETE FROM `srv_session` WHERE `sessionid`='{$sessionID}';");
    }
    
    /**
     * Trigger a garbage collection on the global session information
     * @global type $sql_conx 
     */
    final protected function garbageCollection() {
	global $sql_conx;
	$now = time();
	$sql_conx->query("DELETE FROM `srv_session` WHERE `end_time`<'$now';");
    }
    
    public function getIP() {
	return $this->ip;
    }
    
    public function getUserID() {
	return $this->userid;
    }
}

?>
